﻿
namespace TFSChangeLogCL
{
    using System;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Reflection;
    using System.Threading;
    using System.Xml;
    using TFSChangeLog;
    using TFSChangeLog.DataAccess;
    using TFSChangeLog.GeneralUtilities;
    using TFSChangeLog.Operations.Services;
    using TFSChangeLog.ViewModel;
    using TFSChangeLogCL.GeneralUtilities;

    /// <summary>Summary description for <see cref="TFSChangeLogMain"/> class.</summary>
    internal class TFSChangeLogMain
    {
        /// <summary>Summary description for <c>TFSChangeLogMain</c> method.</summary>
        /// <param name="args">TODO: Summary description for <c>args</c> parameter of type <c>string[]</c>.</param>
        private static void Main(string[] args)
        {
            MainWindowViewModel m_viewModel = new MainWindowViewModel();
            ArgumentParserHelper CommandLineArgs = new ArgumentParserHelper(args);
            
            if (CommandLineArgs["TFSChangeLogConfig"] != null)
            {
                TFSChangeLog.DataAccess.TFSChangeLogStaticConfigs.IsRunningFromCommandPrompt = true;
                if (CommandLineArgs["SilentMode"] == "true")
                    {
                        TFSChangeLog.DataAccess.TFSChangeLogStaticConfigs.IsRunningInSilentMode = true;
                    }

                if (CommandLineArgs["IgnoreXSLT"] == "true")
                {
                    TFSChangeLog.DataAccess.TFSChangeLogStaticConfigs.IsIgnoreXSLT = true;
                    TFSChangeLog.DataAccess.TFSChangeLogStaticConfigs.IsRunningInSilentMode = true;
                }
                ProduceTFSChangeLog(CommandLineArgs["TFSChangeLogConfig"], m_viewModel);
            }
            else ShowTFSChangeLogUsage();
        }

        /// <summary>Summary description for <c>TFSChangeLogMain</c> method.</summary>
        /// <param name="tfsChangeLogConfig">TODO: Summary description for <c>tfsChangeLogConfig</c> parameter of type <c>string</c>.</param>
        /// <param name="m_viewModel">TODO: Summary description for <c>m_viewModel</c> parameter of type <c>TFSChangeLog.ViewModel.MainWindowViewModel</c>.</param>
        private static void ProduceTFSChangeLog(string tfsChangeLogConfig, MainWindowViewModel m_viewModel)
        {
            using (Stream stream = Assembly.GetCallingAssembly().GetManifestResourceStream("TFSChangeLogCL.DataModel.TFSChangeLogConfig.xsd"))
            {
                WriteLineSeparator();
                Console.WriteLine("TFSChangeLogConfig     : " + tfsChangeLogConfig);

                bool isValid = false;
                // return XmlSchema.Read(stream, HandleValidation);
                try
                {
                     isValid = XML_XSD_Validator.Validate(tfsChangeLogConfig, stream);
                }
                catch (XmlException xmlex)
                {
                    Console.WriteLine("ERROR                  : " + xmlex.Message);
                    WriteLineSeparator();
                    return;
                }
                
                TFSChangeLogConfig _tfsChangeLogConfig = new TFSChangeLogConfig();

                bool isChangeLogConfigLoaded;
                isChangeLogConfigLoaded = GenericXmlSerializer<TFSChangeLogConfig>.LoadFromFile(tfsChangeLogConfig, out _tfsChangeLogConfig);

                if (isChangeLogConfigLoaded)
                {
                    Console.WriteLine("TFS Server Path        : " + _tfsChangeLogConfig.ServerPath);
                    Console.WriteLine("TFS Project Name       : " + _tfsChangeLogConfig.ProjectName);
                    Console.WriteLine("TFS Branch Path        : " + _tfsChangeLogConfig.BranchPath);
                    Console.WriteLine("StartFrom ChangeSet    : " + _tfsChangeLogConfig.StartFromChangeSet);
                    Console.WriteLine("EndTo ChangeSet        : " + _tfsChangeLogConfig.EndTochangeSet);
                    WriteLineSeparator();
                    Console.WriteLine();
                    
                    TFSConnection.ConnectToTFS(_tfsChangeLogConfig.ServerPath, _tfsChangeLogConfig.ProjectName);

                    // Check if Project is found.

                    var isTeamProjectFound = TFSConnection.CheckIfProjectExist(_tfsChangeLogConfig.ProjectName);

                    if (isTeamProjectFound == false)
                    {
                        Console.WriteLine(
                            "ERROR: \"{0}\" TFS Project Not Found.",
                            _tfsChangeLogConfig.ProjectName);
                        return;
                    }

                    m_viewModel.progressDialogViewModel.TokenSource = new CancellationTokenSource();
                    m_viewModel.TFSServerName = _tfsChangeLogConfig.ServerPath;
                    m_viewModel.TFSProjectName = _tfsChangeLogConfig.ProjectName;
                    Console.WriteLine("Generating Branch List from TFS ... Please Wait ... ... ... ");
                    SelectProjectService.GetBranchInformation(m_viewModel.progressDialogViewModel);
                    
                    // Check if Branch is found.

                    var isBranchFound = false;

                    foreach (var br in m_viewModel.FirstGeneration)
                    {
                        if (String.Compare(br.Name, _tfsChangeLogConfig.BranchPath.TrimEnd(), StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            br.IsSelected = true;
                            isBranchFound = true;
                            break;
                        }

                        if (br.Children.Count > 0)
                        {
                            CheckForBranch(br.Children, _tfsChangeLogConfig.BranchPath, out isBranchFound);
                        }
                    }

                    if (isBranchFound == false)
                    {
                        Console.WriteLine(
                            "ERROR                  : \"{0}\" Branch is not found.",
                            _tfsChangeLogConfig.BranchPath);
                        WriteLineSeparator();
                        return;
                    }

                    m_viewModel.TFSProjectSelectedBranchName = _tfsChangeLogConfig.BranchPath;
                    m_viewModel.CanExecuteGenerateReleaseNotes = true;
                    m_viewModel.IsFromChangeSetsEnabled = true;
                    m_viewModel.IsToChangeSetsEnabled = true;
                    Console.WriteLine("Generating ChangeSet information from TFS ... Please Wait ... ... ... ");

                    // SelectBranchNodeService.GetChangeSetInformationFromCommandPrompt(m_viewModel, _tfsChangeLogConfig);
                    SelectBranchNodeService.GetChangeSetInformation(m_viewModel);

                    var isFromChangeSetFound = false;

                    foreach (var cs in m_viewModel.FromChangeSets)
                    {
                        if (cs.FromChangeSet.ChangesetId == _tfsChangeLogConfig.StartFromChangeSet)
                        {
                            isFromChangeSetFound = true;
                            cs.IsSelected = true;
                            m_viewModel.SelectedFromChangeSet = cs;
                            break;
                        }
                    }

                    if (isFromChangeSetFound == false)
                    {
                        Console.WriteLine(
                            "ERROR                  : {0} FromChangeSet is not found in Branch {1}", 
                            _tfsChangeLogConfig.StartFromChangeSet,
                            _tfsChangeLogConfig.BranchPath);
                        WriteLineSeparator();
                        return;
                    }

                    // First check if To Changeset value is provided. If not then set latest changeset
                    // as ToChangeSet. Otherwise check if ToChangeSet if found in the selected branch.
                    if (_tfsChangeLogConfig.EndTochangeSet != 0)
                    {
                        var isToChangeSetFound = false;
                        foreach (var cs in m_viewModel.ToChangeSets)
                        {
                            if (cs.ToChangeSet.ChangesetId == _tfsChangeLogConfig.EndTochangeSet)
                            {
                                isToChangeSetFound = true;
                                cs.IsSelected = true;
                                m_viewModel.SelectedToChangeSet = cs;
                                break;
                            }
                        }

                        if (isToChangeSetFound == false)
                        {
                            Console.WriteLine(
                                              "ERROR                  : {0} ToChangeSet is not found in Branch {1}",
                                              _tfsChangeLogConfig.EndTochangeSet,
                                              _tfsChangeLogConfig.BranchPath);
                            WriteLineSeparator();
                            return;
                        }
                    }
                    else if (m_viewModel.ToChangeSets.Count > 0) 
                    {
                        m_viewModel.ToChangeSets[0].IsSelected = true;
                        m_viewModel.SelectedToChangeSet = m_viewModel.ToChangeSets[0];
                    }
                    else
                    {
                        Console.WriteLine(
                                          "ERROR                  : \"{0}\" branch does not contain more then one ChangeSet. \n" +
                                          "Minimum of two changeset are required to generate ChangeLog report.",
                                          _tfsChangeLogConfig.BranchPath);
                        WriteLineSeparator();
                        return;
                    }

                    // Generate Release Notes.
                    Console.WriteLine("Generating Change Log / Release Notes from TFS ... Please Wait ... ... ... ");
                    GenerateReleaseNotesService.GenerateRelaseNotes(m_viewModel);
                    WriteLineSeparator();

                    if (!string.IsNullOrEmpty(_tfsChangeLogConfig.FileExtensions))
                    {

                        // Generate xml changes.
                        m_viewModel.FileExtension = _tfsChangeLogConfig.FileExtensions;
                        Console.WriteLine("Generating xml changes from TFS ... Please Wait ... ... ... ");
                        GenerateXmlChangesService.GenerateXmlChanges(m_viewModel);
                    }

                    WriteLineSeparator();
                }
                else
                {
                    Console.WriteLine("ERROR                  : Loading XML content as TFSChangeLogConfig objects.");
                    WriteLineSeparator();
                }
            }
        }

        /// <summary>Summary description for <c>TFSChangeLogMain</c> method.</summary>
        private static void WriteLineSeparator()
        {
            Console.WriteLine(
                "========================================================================================");
        }

        /// <summary>Summary description for <c>TFSChangeLogMain</c> method.</summary>
        /// <param name="branchViewModel">TODO: Summary description for <c>branchViewModel</c> parameter of type <c>System.Collections.ObjectModel.ObservableCollection{TFSChangeLog.ViewModel.BranchViewModel}</c>.</param>
        /// <param name="branchPath">TODO: Summary description for <c>branchPath</c> parameter of type <c>string</c>.</param>
        /// <param name="isBranchFound">TODO: Summary description for <c>isBranchFound</c> parameter of type <c>bool</c>.</param>
        private static void CheckForBranch(
                                           ObservableCollection<BranchViewModel> branchViewModel,
                                           string branchPath,
                                           out bool isBranchFound)
        {
            isBranchFound = false;
            foreach (var br in branchViewModel)
            {
                if (String.Compare(br.Name, branchPath.TrimEnd(), StringComparison.OrdinalIgnoreCase) == 0)
                {
                    br.IsSelected = true;
                    isBranchFound = true;
                }
                else if (br.Children.Count > 0)
                {
                    CheckForBranch(br.Children, branchPath, out isBranchFound);
                }

                if (isBranchFound == true)
                {
                    break;
                }
            }
        }

        /// <summary>Summary description for <c>TFSChangeLogMain</c> method.</summary>
        private static void ShowTFSChangeLogUsage()
        {
            Console.WriteLine(string.Empty);
            Console.WriteLine("TFSChangeLog applicaiton is used for generating Changesets and WorkItems details based on \n" +
                              "provided starting and ending Changeset information.");
            Console.WriteLine(string.Empty);
            Console.WriteLine("Usage");
            Console.WriteLine("=====");
            Console.WriteLine(string.Empty);
            Console.WriteLine("TFSChangeLog.exe --TFSChangeLogConfig=[TFS ChangeLog Application Configuration File Path]");
            Console.WriteLine("                [--SilentMode]");
            Console.WriteLine("                [--IgnoreXSLT]");
            Console.WriteLine(string.Empty);
            Console.WriteLine("    --TFSChangeLogConfig :  Parameter should points to an XML file that comply to TFSChangeLogConfig.xsd.");
            Console.WriteLine("                            You will find an example configuraiton file named \"TFSChangeLogConfig.xml\" \n" +
                              "                            in the root folder of this application.");
            Console.WriteLine(string.Empty);
            Console.WriteLine("    --SilentMode         :  Optional. Application will now show final HTML output at the end of execution.");
            Console.WriteLine(string.Empty);
            Console.WriteLine("    --IgnoreXSLT         :  Optional. Applicatin will not perform XSLT transformation. This option by default");
            Console.WriteLine("                            also sets --SilentMode to discard generating HTML output.");
            Console.WriteLine(string.Empty);
        }
    }
}
